home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / unix / volume24 / newsgate / part01 next >
Encoding:
Internet Message Format  |  1991-10-09  |  51.9 KB

  1. Subject:  v24i051:  News/mail gateway package, Part01/04
  2. Newsgroups: comp.sources.unix
  3. Approved: rsalz@uunet.UU.NET
  4. X-Checksum-Snefru: a0337cbd c86bfe66 f571c436 de881e78
  5.  
  6. Submitted-by: Rich $alz <rsalz@bbn.com>
  7. Posting-number: Volume 24, Issue 51
  8. Archive-name: newsgate/part01
  9.  
  10. This kit provides two programs for "linking" RFC822 Mail messages and
  11. RFC1076 Usenet News articles.  Each half of the conversion is handled by a
  12. different program, mail2news or news2mail.  A few utility programs are
  13. also included.
  14.  
  15. With these programs and the right set of mail aliases and news sys and
  16. active file entries, it is possible to build any set of moderated,
  17. unmoderated, one-way, or bi-directional gateways between any set of news
  18. and mail groups and lists that your little heart desires.
  19.  
  20. #! /bin/sh
  21. # This is a shell archive.  Remove anything before this line, then feed it
  22. # into a shell via "sh file" or similar.  To overwrite existing files,
  23. # type "sh file -c".
  24. # The tool that generated this appeared in the comp.sources.unix newsgroup;
  25. # send mail to comp-sources-unix@uunet.uu.net if you want that tool.
  26. # Contents:  README MANIFEST gag.1 gag.y regex.c
  27. # Wrapped by rsalz@litchi.bbn.com on Fri Mar 15 16:42:25 1991
  28. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  29. echo If this archive is complete, you will see the following message:
  30. echo '          "shar: End of archive 1 (of 4)."'
  31. if test -f 'README' -a "${1}" != "-c" ; then 
  32.   echo shar: Will not clobber existing file \"'README'\"
  33. else
  34.   echo shar: Extracting \"'README'\" \(3833 characters\)
  35.   sed "s/^X//" >'README' <<'END_OF_FILE'
  36. XIntroduction
  37. X------------
  38. XThis kit provides two programs for "linking" RFC822 Mail messages and
  39. XRFC1076 Usenet News articles.  Each half of the conversion is handled by a
  40. Xdifferent program, mail2news or news2mail.  A few utility programs are
  41. Xalso included.
  42. X
  43. XWith these programs and the right set of mail aliases and news sys and
  44. Xactive file entries, it is possible to build any set of moderated,
  45. Xunmoderated, one-way, or bi-directional gateways between any set of news
  46. Xand mail groups and lists that your little heart desires.
  47. X
  48. XIf you run a small site with a couple of mostly-local mailing lists, you
  49. Xprobably don't want to bother setting this stuff up.  Instead, either
  50. Xconvert everything directly to News, or set up local moderated groups.  On
  51. Xthe other hand, if you provide gateway service to the Internet (e.g., UCB)
  52. Xor large organization, then this stuff is for you.  News, especially with
  53. Xthe proliferation of NNTP (RFC977) and related clients, is generally more
  54. Xefficient than mail for disk space, CPU cycles, and network usage.
  55. X
  56. XThe programs work with Sendmail or MMDF and News 2.11.8 or later.  I don't
  57. Xknow of anything off-hand that would prevent this from working with C news
  58. X(did Erik ever say thank you, Henry?).  We've only run the programs on BSD
  59. Xhosts, but a start toward a System V port has been made.  Who knows, it
  60. Xmight even work right now.
  61. X
  62. XErik Fair <fair@apple.com> wrote the original version of this package a
  63. Xcouple of years ago as "nrecnews" distributed with 2.11 and as "gateway", a
  64. Xvery tricky awk/shell/sed script.  I got copies, and recoded it all in C.
  65. XI also completely overhauled nrecnews, changed the names, added some
  66. Xutility programs, and wrote the documentation.  It seems pretty solid now,
  67. Xand is processing a few hundred messages a week at BBN and elsewhere.
  68. X
  69. XInstallation
  70. X------------
  71. XMail2news uses the date parser from the 2.11 netnews distribution; edit
  72. Xthe Makefile to point to where you keep your source.  Next, edit gate.h as
  73. Xappropriate for your system.  There are some fairly detailed comments
  74. Xexplaining the meaning of the #define's, but good luck.  Unfortunately,
  75. Xthis is one of those things that you have to already know a fair bit about
  76. Xbefore you can use it.  As one way up the learning curve, play with the
  77. Xgag -- the hardest part is almost always getting the right aliases and news
  78. Xentries set up.
  79. X
  80. XThe "signoff" code is pulled out into a separate program and is also part
  81. Xof mail2news.  This is so that a properly paranoid administrator can trap
  82. Xthe exit code, and forward rejected postings to a human to verify.  If
  83. Xyou trust the heuristics in that program, just turn on the -F flag.
  84. X
  85. XAt this point I should be telling you how to set up the different types of
  86. Xgroups, but I'm too burnt out on this to bother.  If someone has some
  87. Xwords here to get me started, I'd appreciate it.
  88. X
  89. XFlaws
  90. X-----
  91. XCross-posting and multiple mail recipients are not handled very well.
  92. XCross-post means each mailing list gets a separate message.  Does
  93. XB news's multi-cast fix this, perhaps?
  94. X
  95. XSomeone sending mail to lista and listb means the message only goes into
  96. Xnews.list.a, or news.list.b, depending on which gateway alias gets it
  97. Xfirst, which isn't great.  One hack, to avoid losing messages, is to munge
  98. Xthe message-id to put the newsgroup name in there.
  99. X
  100. XHow do you bypass the "more included than new text" check in inews?
  101. X
  102. XFinally
  103. X-------
  104. XI am maintaining this release, but Erik is still involved in the issues
  105. Xand might be interested in what you have to say.  There is a mailing list
  106. Xfor sites doing this in a big way, primarily on the Internet.  Write
  107. Xto news-n-mail-request@bbn.com to be added.  Please don't ask to join
  108. Xif you're only doing local gateways of a couple of groups.
  109. X
  110. XIf you don't send e-mail, then use comp.mail.misc and news.software.b;
  111. Xcross-post.
  112. X
  113. XRich $alz
  114. Xrsalz@bbn.com
  115. END_OF_FILE
  116.   if test 3833 -ne `wc -c <'README'`; then
  117.     echo shar: \"'README'\" unpacked with wrong size!
  118.   fi
  119.   # end of 'README'
  120. fi
  121. if test -f 'MANIFEST' -a "${1}" != "-c" ; then 
  122.   echo shar: Will not clobber existing file \"'MANIFEST'\"
  123. else
  124.   echo shar: Extracting \"'MANIFEST'\" \(1811 characters\)
  125.   sed "s/^X//" >'MANIFEST' <<'END_OF_FILE'
  126. X   File Name        Archive #    Description
  127. X----------------------------------------------------------
  128. XREADME                     1    Installation notes
  129. XMANIFEST                   1    This shipping list
  130. XMakefile                   4    Guess...
  131. XTODO                       4    Stuff I haven't gotten around to yet
  132. Xgag.1                      1    Manual page for gag
  133. Xgag.y                      1    Gateway alias generator program
  134. Xgate.h                     3    Header file, #include'd by everyone
  135. Xhdr.c                      3    Header-cracking and address re-writing routines
  136. Xlex.l                      3    Tokenizer for gag
  137. Xmail-interface             3    Front-end to MMDF or sendmail
  138. Xmail2news.1                3    Manual page for mail2news
  139. Xmail2news.c                2    Main program for mail->news gateway
  140. Xmisc.c                     3    Support routines for both programs
  141. Xmkmailpost.1               4    Manual page for mkmailpost
  142. Xmkmailpost.sh              2    Turn active file into "mailpost" commands
  143. Xnews2mail.1                3    Manual page for news2mail
  144. Xnews2mail.c                2    Main program for news->mail gateway
  145. Xnews2mail.sh               4    A script version of news2mail
  146. Xpatchlevel.h               4    Misteak recorder
  147. Xregex.3                    2    Manual page for regex
  148. Xregex.c                    1    Regular-expression matching routines
  149. Xrfc822.c                   2    Reading and writing mail and news headers
  150. Xsignoff.1                  4    Manual page for signoff
  151. Xsignoff.c                  3    Program to filter out "add me" requests
  152. Xstr.c                      4    String and support routines for mail2news
  153. Xsysexits.h                 3    System exit codes
  154. Xtest-addr                  4    Test cases for address-rewriting routines
  155. Xtest-gag                   4    Test cases for gag program
  156. Xuucp-2-inet                3    Mapping of UUCP to Internet hostnames
  157. END_OF_FILE
  158.   if test 1811 -ne `wc -c <'MANIFEST'`; then
  159.     echo shar: \"'MANIFEST'\" unpacked with wrong size!
  160.   fi
  161.   # end of 'MANIFEST'
  162. fi
  163. if test -f 'gag.1' -a "${1}" != "-c" ; then 
  164.   echo shar: Will not clobber existing file \"'gag.1'\"
  165. else
  166.   echo shar: Extracting \"'gag.1'\" \(8467 characters\)
  167.   sed "s/^X//" >'gag.1' <<'END_OF_FILE'
  168. X.\" $Header: /nfs/papaya/u2/rsalz/src/newsgate/src/RCS/gag.1,v 1.5 91/02/12 14:43:31 rsalz Exp $
  169. X.TH GAG 1 LOCAL
  170. X.SH NAME
  171. Xgag \- Gateway alias generator
  172. X.SH SYNOPSIS
  173. X.in +.5i
  174. X.na
  175. X.ti -.5i
  176. X.B gag
  177. X[
  178. X.B \- a
  179. X] [
  180. X.BI \-b bbn_file
  181. X] [
  182. X.BI \-d mmdf_dir
  183. X] [
  184. X.BI \-s sendmail_file
  185. X] [
  186. X.BI \-n news_file
  187. X] [
  188. X.BI \-t PP_shell
  189. X] [
  190. X.BI \-u PP_user
  191. X] [
  192. X.B \-b
  193. X] [
  194. X.B \-p
  195. X] [
  196. X.I file
  197. X]
  198. X.ad
  199. X.in -.5i
  200. X.SH DESCRIPTION
  201. X.I Gag
  202. Xreads a control file and builds entries for
  203. X.IR sendmail (8),
  204. X.IR BBN ,
  205. X.IR MMDF (8),
  206. Xand
  207. X.IR PP (8)
  208. Xalias files, as well as
  209. X.IR Netnews (1)
  210. Xsys file entries.
  211. XIt is an auxiliary program for helping to maintain a mail/news
  212. Xgateway operation.
  213. XA typical
  214. X.I gag
  215. Xfile sets up default values for all the parameters, then contains a list
  216. Xof newsgroup\-mailing list pairs.
  217. XGroup-specific values can override the defaults.
  218. X.PP
  219. X.I Gag
  220. Xinput is fairly free-form.
  221. XIt ignores C-style comments, and whitespace is allowed anywhere.
  222. XThere are a couple of dozen keywords, and case is significant; most
  223. Xof the keywords are parameters used to control the gatewaying.
  224. XQuoted strings are written as they are in C, except they may not
  225. Xspan lines.
  226. X.PP
  227. XUsing the parameters enumerated below,
  228. X.I gag
  229. Xcan write six different sets of alias files:
  230. X.RS
  231. X.ta \w'Sendmail  'u
  232. X.nf
  233. XBBN    if the ``\-b'' flag is used
  234. XMMDF    if the ``\-m'' flag is used
  235. Xnews    if the ``\-n'' flag is used
  236. XSendmail    if the ``\-s'' flag is used
  237. XPP shell    If the ``\-t'' flag is used
  238. XPP user    if the ``\-u'' flag is used
  239. X.fi
  240. X.RE
  241. XAny combination of these flags is allowed.
  242. X.PP
  243. X.I Gag
  244. Xnormally complains about attempts to gateway groups that are not in
  245. Xthe news active file; use the ``\-a'' suppresses this check, assuming
  246. Xthat all named groups are valid.
  247. X.PP
  248. XBBN-style
  249. Xaliases can't pipe into a command with parameters.
  250. XFor example,
  251. X.I sendmail
  252. Xcan have an entry like this in
  253. X.IR /usr/lib/aliases (5):
  254. X.RS
  255. X.ta \w'post-bboard:  'u
  256. X.nf
  257. Xpost-bboard:    "|/usr/lib/news/mail2news -n bbn.bboard \e
  258. X    -o 'BBN News/Mail Gateway' \e
  259. X    -d bbn"
  260. X.fi
  261. X.RE
  262. XWith BBN, it is necessary to create an alias that feeds into a custom script:
  263. X.RS
  264. X.ta \w'bboard-gate:  'u
  265. X.nf
  266. Xbboard-gate:    @mailer.bbn.com { "news|/usr/lib/news/.admin/gate-bboard" }
  267. X    bboard-gate@mailer.bbn.com
  268. X.fi
  269. X.RE
  270. X.I Gag
  271. Xwill also create the utility script invoked by the above alias:
  272. X.RS
  273. X.ta \w'exec 'u
  274. X.nf
  275. X#! /bin/sh
  276. X##  This script is on the "bboard" mailing list.
  277. Xexec /usr/lib/news/mail2news -n bbn.bboard \e
  278. X    -o "BBN News/Mail Gateway" \e
  279. X    -d bbn
  280. X.fi
  281. X.RE
  282. XTo create these scripts, use the ``\-d'' flag to name the directory where
  283. Xthey should be created; ``\-d .'' will create them in the current directory.
  284. X.PP
  285. X.I MMDF
  286. Xaliases are similar to
  287. X.IR sendmail 's,
  288. Xexcept that the the scripts are run under a specified user id
  289. X(see below).
  290. X.PP
  291. X.I PP
  292. Xuses two files, a shell and user file, whose format is not described here.
  293. X.PP
  294. XSome sites want to create mail aliases that forward into each newsgroup;
  295. Xthat is, mail sent to ``comp-foo-bar'' should get posted to the ``comp.foo.bar''
  296. Xnewsgroup.
  297. XIf the ``\-p'' flag is used, then each gatewayed group will get such an
  298. Xalias created.
  299. XThe
  300. X.IR mkmailpost (1L)
  301. Xcommand can be used to create
  302. X.I gag
  303. X``mailpost'' commands for all entries in the news active file.
  304. XNote that using
  305. X.I mkmailpost
  306. Xand the ``\-p'' flag will almost certainly result in the creation of duplicate
  307. Xaliases.
  308. X.PP
  309. XThe parameters that control the gatewaying are:
  310. X.IP directory
  311. XThe directory where the BBN alias scripts are kept.
  312. X(In the above example, the directory is
  313. X.IR /usr/lib/news/.admin .)
  314. X.IP distributions
  315. XA space-separated list of distributions to forward from news to mail.
  316. XIn most cases, this will be the full set of distributions received, but
  317. Xit can be convenient, for example, to not forward regional articles out
  318. Xto a world-wide mailing list.
  319. XWith distributions set to ``world usa na'' then the news sys entry
  320. Xfor ``comp.foo'' will have this in the second field:
  321. X.in +.5i
  322. X.nf
  323. X<site>:\e
  324. X  world,!world.all,usa,!usa.all,na,!na.all,comp.foo,!comp.foo.all\e
  325. X  <rest of entry>
  326. X.in -.5i
  327. X.fi
  328. X.IP "inews flags"
  329. XThese are flags to pass on to
  330. X.IR inews (8)
  331. Xwhen gatewaying a mail message into netnews.
  332. XThey are put on the
  333. X.I news2mail
  334. Xcommand line, which will pass them along.
  335. XA common use is to set a default distribution or organization.
  336. X.IP mail2news
  337. XThe full pathname of the
  338. X.I mail2news
  339. Xprogram.
  340. X.IP mailcontact
  341. XThis is the name of the person listed in the ``For more information, contact''
  342. Xpart of the header generated by
  343. X.IR news2mail.
  344. X>>WHAT DOES GATEWAY DO??<<
  345. X.IP mailhost
  346. XWhen remote mailing lists are gatewayed into local newsgroups, it can
  347. Xoften be convenient to provide a local alias that forwards on to the
  348. Xremote host.
  349. XFor example, if the list ``info-foo'' is maintained at ``vax.host.edu''
  350. Xthen it is possible to create a local alias that just forwards to
  351. X``info-foo@vax.host.edu.''
  352. X.IP "mailinglist"
  353. XIf set to ``true,'' then
  354. X.I gag
  355. Xwill write aliases that forward on to the list at the current mailhost; if
  356. Xset to ``false'' than no such aliases will be written.
  357. X.IP moderator
  358. XIf set, then the value is put on the
  359. X.I mail2news
  360. Xcommand line with the ``\-a'' flag.
  361. XThis is useful for making a semi-moderated one-way gateway.
  362. X.IP news2mail
  363. XThe full pathname of the
  364. X.I news2mail
  365. Xprogram.
  366. X.IP organization
  367. XIf set, then the value is put on the
  368. X.I mail2news
  369. Xcommand line with the ``\-o'' flag.
  370. X.IP owner
  371. XIf set, then all
  372. X.I sendmail
  373. Xaliases also have an ``owner\-'' version, with this value as the
  374. Xrecipient, to receive trouble reports.
  375. X.IP requestaddr
  376. XMost mailing lists have a ``\-request'' address to handle list administration.
  377. XWhen gatewaying the list ``info-foo'' if the maintenance address isn't
  378. X``info-foo-request'' set this parameter to the proper address.
  379. X.IP site
  380. XThis is the name of the site to use in the news sys file; ``gateway'' is
  381. Xa common choice.
  382. X.IP user
  383. XWhen running scripts under
  384. X.I MMDF
  385. X(either normal or with the BBN style)
  386. Xa userid to setuid to must be given.
  387. X.PP
  388. XNote that there is some overlap in these parameters.
  389. XIn particular the ``moderator'' and ``organization'' parameters can really
  390. Xbe subsumed by the ``inews flags'' parameter.
  391. XThey are explicitly called out, however, for convenience in specifying
  392. Xthe types of gatewaying.
  393. XFor example, while all gatewayed groups might go out with the same
  394. Xdistribution, only some might need an
  395. X.I Approved:
  396. Xheader line.
  397. X.SH "THE LANGUAGE"
  398. XA
  399. X.I gag
  400. Xfile is composed of intermixed parts of three different constructs:
  401. Xdefaults, mail/news posting entries, mail/news gateway entries.
  402. X.PP
  403. XIndividual groups can override the default parameters.
  404. XThe defaults can be changed at any time, and retain the new value for
  405. Xthe rest of the file or until changed again.
  406. XFor example, most mail aliases will be ``owned'' by
  407. X.IR postmaster ,
  408. Xbut it might be convenient to set the forwarding address on specific
  409. Xaliases to someone else.
  410. XFor example:
  411. X.RS
  412. X.DT
  413. X.nf
  414. X/* Send gateway complaints to postmaster */
  415. Xdefault owner = "postmaster";
  416. X
  417. X/* The "animals" list is privately maintained. */
  418. Xgateway bbn.animals animal-rights
  419. X    owner = "canus-major";
  420. X.fi
  421. X.RE
  422. XThe syntax is explained in more detail, below.
  423. X.PP
  424. XA default parameter assignment looks like one of the following:
  425. X.RS
  426. X.DT
  427. X.nf
  428. X\fBdefault\fP <parameter> \fB= true ;\fP
  429. X\fBdefault\fP <parameter> \fB= false ;\fP
  430. X\fBdefault\fP <parameter> \fB=\fP "string value" \fB;\fP
  431. X\fBdefault\fP <parameter> \fB= dotify (\fP "value" \fB) ;\fP
  432. X.fi
  433. X.RE
  434. XThe last form is used to translate mixed-case strings into the prefix-period
  435. Xform used by mail2news, q.v.
  436. X.PP
  437. XA gateway declaration looks like this:
  438. X.RS
  439. X.DT
  440. X.nf
  441. X\fBgateway\fP <newsgroup> <mailinglist>
  442. X    [ parameter settings ] \fB;\fP
  443. X.fi
  444. X.RE
  445. XThe parameter settings are like the default settings shown above, except
  446. Xthat the word ``default'' is left off, as are all semicolons but the
  447. Xlast one.
  448. X.PP
  449. XTo set up a simple unidirectional newsgroup/mailing list gateway, use a
  450. X``mailpost'' declaration:
  451. X.RS
  452. X.DT
  453. X.nf
  454. X\fBmailpost\fP <newsgroup> \fB;\fP
  455. X.fi
  456. X.RE
  457. X.SH "BUGS AND CAVEATS"
  458. XThis program is a collection of memory leaks; as it runs for a very short
  459. Xtime that's okay.
  460. X.PP
  461. XIn generating news
  462. X.I sys
  463. Xfile entries, remember that the command is a
  464. X.IR sprintf (3)
  465. Xformat string, and any percent signs
  466. X.RI ( % )
  467. Xmust be doubled or they will be taken as a formatting control.
  468. X.SH "SEE ALSO"
  469. Xmail2news(1L), mkmailpost(1L), news2mail(1L).
  470. X.SH AUTHORS
  471. XRich $alz <rsalz@bbn.com>, replacing some
  472. X.I m4
  473. Xscripts that
  474. X.br
  475. XErik E. Fair <fair@apple.com> wrote.
  476. X.br
  477. XPiete Brooks <pb@computer-lab.cambridge.ac.uk> provided the PP support.
  478. END_OF_FILE
  479.   if test 8467 -ne `wc -c <'gag.1'`; then
  480.     echo shar: \"'gag.1'\" unpacked with wrong size!
  481.   fi
  482.   # end of 'gag.1'
  483. fi
  484. if test -f 'gag.y' -a "${1}" != "-c" ; then 
  485.   echo shar: Will not clobber existing file \"'gag.y'\"
  486. else
  487.   echo shar: Extracting \"'gag.y'\" \(14642 characters\)
  488.   sed "s/^X//" >'gag.y' <<'END_OF_FILE'
  489. X%{
  490. X/*
  491. X**  GAG
  492. X**
  493. X**  Mail/news gateway alias generator.
  494. X*/
  495. X#define MAINLINE
  496. X#include "gate.h"
  497. X#ifdef    RCSID
  498. Xstatic char RCS[] =
  499. X    "$Header: /nfs/papaya/u2/rsalz/src/newsgate/src/RCS/gag.y,v 1.5 91/02/12 14:43:44 rsalz Exp $";
  500. X#endif    /* RCSID */
  501. X
  502. X#define EMPTY(p)        ((p) == NULL || (p)[0] == '\0')
  503. X
  504. Xchar        *Pname;            /* Program name            */
  505. X
  506. Xint        Errors;            /* Did user screw up?        */
  507. XSTATIC int    NoGroupCheck;        /* Don't check if valid group?    */
  508. XSTATIC int    PostViaMail;        /* Make post-news-group alias?    */
  509. XSTATIC char    *OutDir;        /* Directory for BBN scripts    */
  510. XSTATIC FILE    *bbn;            /* File for BBN-style aliases    */
  511. XSTATIC FILE    *ppuser;        /* File for PP user aliases    */
  512. XSTATIC FILE    *ppshell;        /* File for PP shell aliases    */
  513. XSTATIC FILE    *mmdf;            /* File for MMDF aliases    */
  514. XSTATIC FILE    *sendmail;        /* File for Sendmail aliases    */
  515. XSTATIC FILE    *news;            /* File for sys file entries    */
  516. X
  517. XSTATIC char    *CurDirectory,        *DefDirectory;
  518. XSTATIC char    **CurDistribs,        **DefDistribs;
  519. XSTATIC int    CurDoMailinglist,    DefDoMailinglist;
  520. XSTATIC char    *CurFlags,        *DefFlags;
  521. XSTATIC char    *CurMail2news,        *DefMail2news;
  522. XSTATIC char    *CurMailcontact,    *DefMailcontact;
  523. XSTATIC char    *CurMailhost,        *DefMailhost;
  524. XSTATIC char    *CurModerator,        *DefModerator;
  525. XSTATIC char    *CurNews2mail,        *DefNews2mail;
  526. XSTATIC char    *CurOrganization,    *DefOrganization;
  527. XSTATIC char    *CurOwner,        *DefOwner;
  528. XSTATIC char    *CurRequestAddr,    *DefRequestAddr;
  529. XSTATIC char    *CurSite,        *DefSite;
  530. XSTATIC char    *CurUser,        *DefUser;
  531. X
  532. Xextern time_t    time();
  533. X%}
  534. X
  535. X%union {
  536. X    char    *String;
  537. X    int        Bool;
  538. X}
  539. X
  540. X%token    tDEFAULT tDIRECTORY tDISTRIBUTIONS tDOTIFY tFALSE tGATEWAY tFLAGS
  541. X%token    tID tINEWS tMAIL2NEWS tMAILCONTACT tMAILHOST tMAILINGLIST
  542. X%token    tMAILPOST tMODERATOR tNEWS2MAIL tORGANIZATION tOWNER tREQUESTADDR
  543. X%token    tSITE tTRUE tUSER
  544. X
  545. X%type    <String>    tID value
  546. X%type    <Bool>        boolean
  547. X
  548. X%%
  549. X
  550. Xfile    : /* NULL */
  551. X    | file block ';'
  552. X    | file default ';'
  553. X    | file mpost ';'
  554. X    | file error ';' {
  555. X#ifdef    lint
  556. X        /* Compulsive... */
  557. X        if (Errors)
  558. X        YYERROR;
  559. X#endif    /* lint */
  560. X    }
  561. X    ;
  562. X
  563. Xdefault    : tDEFAULT tDIRECTORY value    { DefDirectory = $3; }
  564. X    | tDEFAULT tDISTRIBUTIONS value    { (void)Split($3, &DefDistribs, '\0'); }
  565. X    | tDEFAULT tINEWS tFLAGS value    { DefFlags = $4; }
  566. X    | tDEFAULT tMAIL2NEWS value    { DefMail2news = $3; }
  567. X    | tDEFAULT tMAILCONTACT value    { DefMailcontact = $3; }
  568. X    | tDEFAULT tMAILHOST value    { DefMailhost = $3; }
  569. X    | tDEFAULT tMAILINGLIST boolean    { DefDoMailinglist = $3; }
  570. X    | tDEFAULT tMODERATOR value    { DefModerator = $3; }
  571. X    | tDEFAULT tNEWS2MAIL value    { DefNews2mail = $3; }
  572. X    | tDEFAULT tORGANIZATION value    { DefOrganization = $3; }
  573. X    | tDEFAULT tOWNER value        { DefOwner = $3; }
  574. X    | tDEFAULT tREQUESTADDR value    { DefRequestAddr = $3; }
  575. X    | tDEFAULT tSITE value        { DefSite = $3; }
  576. X    | tDEFAULT tUSER value        { DefUser = $3; }
  577. X    ;
  578. X
  579. Xblock    : op_init tGATEWAY tID tID op_set {
  580. X        if (!Errors && ValidNewsgroup($3))
  581. X        WriteOne($3, $4);
  582. X    }
  583. X    ;
  584. X
  585. Xmpost    : op_init tMAILPOST tID op_set {
  586. X        char    *GroupasMail;
  587. X
  588. X        if (!Errors && ValidNewsgroup($3)) {
  589. X        GroupasMail = Dot2Dash($3);
  590. X        if (bbn)
  591. X            BBNpostviamail($3, GroupasMail);
  592. X        if (sendmail)
  593. X            Fprintf(sendmail, "%s: \"|%s -n %s\"\n",
  594. X            GroupasMail, CurMail2news, $3);
  595. X        if (mmdf)
  596. X            Fprintf(mmdf, "%s: \"%s|%s -n %s\"\n",
  597. X            GroupasMail, CurUser, CurMail2news, $3);
  598. X        if (ppuser)
  599. X            Fprintf(ppuser, "%s:shell\n", GroupasMail);
  600. X        if (ppshell)
  601. X            Fprintf(ppshell, "%s:%s,,%s -n %s\n",
  602. X            GroupasMail, CurUser, CurMail2news, $3);
  603. X        }
  604. X    }
  605. X    ;
  606. X
  607. Xop_init    : /* NULL */ {
  608. X        CurDoMailinglist = DefDoMailinglist;
  609. X        CurDistribs = DefDistribs;
  610. X        CurDirectory = DefDirectory;
  611. X        CurFlags = DefFlags;
  612. X        CurMail2news = DefMail2news;
  613. X        CurMailhost = DefMailhost;
  614. X        CurMailcontact = DefMailcontact;
  615. X        CurModerator = DefModerator;
  616. X        CurNews2mail = DefNews2mail;
  617. X        CurOrganization = DefOrganization;
  618. X        CurOwner = DefOwner;
  619. X        CurRequestAddr = DefRequestAddr;
  620. X        CurSite = DefSite;
  621. X        CurUser = DefUser;
  622. X    }
  623. X    ;
  624. X
  625. Xop_set    : /* NULL */
  626. X    | an_opt op_set
  627. X    ;
  628. X
  629. Xan_opt    : tDIRECTORY value    { CurDirectory = $2; }
  630. X    | tDISTRIBUTIONS value    { (void)Split($2, &CurDistribs, '\0'); }
  631. X    | tINEWS tFLAGS value    { CurFlags = $3; }
  632. X    | tMAIL2NEWS value    { CurMail2news = $2; }
  633. X    | tMAILCONTACT value    { CurMailcontact = $2; }
  634. X    | tMAILHOST value    { CurMailhost = $2; }
  635. X    | tMAILINGLIST boolean    { CurDoMailinglist = $2; }
  636. X    | tMODERATOR value    { CurModerator = $2; }
  637. X    | tNEWS2MAIL value    { CurNews2mail = $2; }
  638. X    | tORGANIZATION value    { CurOrganization = $2; }
  639. X    | tOWNER value        { CurOwner = $2; }
  640. X    | tREQUESTADDR value    { CurRequestAddr = $2; }
  641. X    | tSITE value        { CurSite = $2; }
  642. X    | tUSER value        { CurUser = $2; }
  643. X    ;
  644. X
  645. Xvalue    : '=' tID {
  646. X        $$ = $2;
  647. X    }
  648. X    | '=' tDOTIFY '(' tID ')' {
  649. X        $$ = Dotify($4);
  650. X    }
  651. X    ;
  652. X
  653. Xboolean    : '=' tTRUE {
  654. X        $$ = TRUE;
  655. X    }
  656. X    | '=' tFALSE {
  657. X        $$ = FALSE;
  658. X    }
  659. X    ;
  660. X%%
  661. X
  662. X
  663. X/*
  664. X**  Copy the string s turning all '.' into '-'.
  665. X*/
  666. XSTATIC char *
  667. XDot2Dash(s)
  668. X    register char    *s;
  669. X{
  670. X    register char    *p;
  671. X    char        *save;
  672. X
  673. X    for (save = p = COPY(s); *s; s++)
  674. X    *p++ = *s == '.' ? '-' : *s;
  675. X    *p = '\0';
  676. X    return save;
  677. X}
  678. X
  679. X
  680. X/*
  681. X**  Copy the string s putting a '.' before all uppercase letters and '.'.
  682. X*/
  683. XSTATIC char *
  684. XDotify(s)
  685. X    register char    *s;
  686. X{
  687. X    register char    *p;
  688. X    char        *save;
  689. X
  690. X    for (save = p = NEW(char, strlen(s) * 2 + 1); *s; *p++ = *s++)
  691. X    if (*s == '.' || isupper(*s))
  692. X        *p++ = '.';
  693. X    *p = '\0';
  694. X    return save;
  695. X}
  696. X
  697. X
  698. X/*
  699. X**  Check if the newsgroup exists in the ACTIVE file.
  700. X*/
  701. XSTATIC int
  702. XValidNewsgroup(Group)
  703. X    register char    *Group;
  704. X{
  705. X    static char        **File;
  706. X    register char    **p;
  707. X    register char    *q;
  708. X
  709. X    if (NoGroupCheck)
  710. X    return TRUE;
  711. X
  712. X    if (File == NULL)
  713. X    /* Read in active file, trim to just the newsgroup names. */
  714. X    for (p = File = ReadFile(ACTIVE); *p; p++)
  715. X        if (q = IDX(*p, ' '))
  716. X        *q = '\0';
  717. X
  718. X    for (p = File; *p; p++)
  719. X    if (EQ(*p, Group))
  720. X        return TRUE;
  721. X
  722. X    Fprintf(stderr, "%s: ignoring invalid newsgroup \"%s\".\n", Pname, Group);
  723. X    return FALSE;
  724. X}
  725. X
  726. X
  727. X/*
  728. X**  Create a BBN alias set so that users can mail into a newsgroup
  729. X**  as if it were a mailing list.
  730. X*/
  731. XSTATIC void
  732. XBBNpostviamail(Ngroup, GroupasMail)
  733. X    char        *Ngroup;
  734. X    char        *GroupasMail;
  735. X{
  736. X    register FILE    *F;
  737. X    char        buff[SM_SIZE];
  738. X
  739. X    /* Create a post-news-group alias which pipes into
  740. X     * the /bin/dir/post-news-group script. */
  741. X    Fprintf(bbn, "post-%s: @%s { \"%s|%s/post-%s\" }\n",
  742. X    GroupasMail, CurMailhost, CurUser, CurDirectory, GroupasMail);
  743. X    Fprintf(bbn, "\tpost-%s@%s\n", GroupasMail, CurMailhost);
  744. X
  745. X    /* Write a post-news-script which calls mail2news. */
  746. X    if (OutDir) {
  747. X
  748. X    /* Open the file. */
  749. X    (void)sprintf(buff, "%s/post-%s", OutDir, GroupasMail);
  750. X    (void)unlink(buff);
  751. X    if ((F = fopen(buff, "w")) == NULL) {
  752. X        Fprintf(stderr, "%s:  Can't open \"%s\" for output, %s.\n",
  753. X        Pname, buff, strerror(errno));
  754. X        exit(1);
  755. X    }
  756. X
  757. X    /* Write the script. */
  758. X    Fprintf(F, "#! /bin/sh\n");
  759. X    Fprintf(F, "## This script forwards into the \"%s\" newsgroup.\n",
  760. X        Ngroup);
  761. X    Fprintf(F, "exec %s -n %s\n", CurMail2news, Ngroup);
  762. X
  763. X    /* Close the file. */
  764. X    (void)fclose(F);
  765. X    (void)chmod(buff, 0755);
  766. X    }
  767. X}
  768. X
  769. X
  770. X/*
  771. X**  Write out one newsgroup/mailing list gatewaying entry.  This is where
  772. X**  the real work is done.  We do BBN, MMDF, Sendmail, and news/sys file
  773. X**  entries here.
  774. X*/
  775. XSTATIC void
  776. XWriteOne(Ngroup, Mlist)
  777. X    register char    *Ngroup;
  778. X    register char    *Mlist;
  779. X{
  780. X    register char    **p;
  781. X    register FILE    *F;
  782. X    register char    *GroupasMail;
  783. X    char        buff[SM_SIZE];
  784. X
  785. X    GroupasMail = Dot2Dash(Ngroup);
  786. X
  787. X    if (bbn) {
  788. X    /* Create an alias that forwards to the script. */
  789. X    Fprintf(bbn, "\n##  Add this to the \"%s\" mailing list.\n", Mlist);
  790. X    Fprintf(bbn, "%s-gate: @%s { \"%s|%s/gate-%s\" }\n",
  791. X        Mlist, CurMailhost, CurUser, CurDirectory, Mlist);
  792. X    Fprintf(bbn, "\t%s-gate@%s\n", Mlist, CurMailhost);
  793. X
  794. X    /* Write the script. */
  795. X    if (OutDir) {
  796. X        if (IDX(CurOrganization, '"')) {
  797. X        yyerror("Can't have \" in organization name");
  798. X        free(GroupasMail);
  799. X        return;
  800. X        }
  801. X
  802. X        /* Open the file. */
  803. X        (void)sprintf(buff, "%s/gate-%s", OutDir, Mlist);
  804. X        (void)unlink(buff);
  805. X        if ((F = fopen(buff, "w")) == NULL) {
  806. X        Fprintf(stderr, "%s:  Can't open \"%s\" for output, %s.\n",
  807. X            Pname, buff, strerror(errno));
  808. X        exit(1);
  809. X        }
  810. X
  811. X        /* Write it. */
  812. X        Fprintf(F, "#! /bin/sh\n");
  813. X        Fprintf(F, "## This script is on the \"%s\" mailing list.\n",
  814. X        Mlist);
  815. X        Fprintf(F, "exec %s -n %s", CurMail2news, Ngroup);
  816. X        if (!EMPTY(CurOrganization))
  817. X        fprintf(F, "\\\n\t-o \"%s\"", CurOrganization);
  818. X        if (!EMPTY(CurModerator))
  819. X        Fprintf(F, "\\\n\t-a %s", CurModerator);
  820. X        if (!EMPTY(CurFlags))
  821. X        Fprintf(F, " \\\n\t%s", CurFlags);
  822. X        Fprintf(F, "\n");
  823. X
  824. X        /* Close it. */
  825. X        (void)fclose(F);
  826. X        (void)chmod(buff, 0755);
  827. X    }
  828. X
  829. X    if (PostViaMail)
  830. X        BBNpostviamail(Ngroup, GroupasMail);
  831. X    }
  832. X
  833. X    if (sendmail || mmdf || ppshell || ppuser) {
  834. X    if (IDX(CurOrganization, '\'')) {
  835. X        yyerror("Can't have ' in organization name");
  836. X        free(GroupasMail);
  837. X        return;
  838. X    }
  839. X    /* Does it make sense to do this? */
  840. X    if (!EMPTY(CurModerator) && CurDoMailinglist)
  841. X        Fprintf(stderr, "Warning:  group %s is moderated and mailable.\n",
  842. X        Ngroup);
  843. X    }
  844. X
  845. X    if (sendmail) {
  846. X    Fprintf(sendmail, "\n## %s <==> %s gateway\n", Ngroup, Mlist);
  847. X    Fprintf(sendmail, "%s%s: %s@%s\n",
  848. X        CurDoMailinglist ? "" : "#", Mlist, Mlist, CurMailhost);
  849. X    if (!EMPTY(CurOwner))
  850. X        Fprintf(sendmail, "%sowner-%s: %s\n",
  851. X        CurDoMailinglist ? "" : "#", Mlist, CurOwner);
  852. X    Fprintf(sendmail, "post-%s: \"|%s -n %s", Mlist, CurMail2news, Ngroup);
  853. X    if (!EMPTY(CurOrganization))
  854. X        Fprintf(sendmail, " -o '%s'", CurOrganization);
  855. X    if (!EMPTY(CurFlags))
  856. X        Fprintf(sendmail, " %s", CurFlags);
  857. X    if (!EMPTY(CurModerator))
  858. X        Fprintf(sendmail, " -a %s", CurModerator);
  859. X    Fprintf(sendmail, "\"\n");
  860. X    if (!EMPTY(CurOwner))
  861. X        Fprintf(sendmail, "owner-post-%s: %s\n", Mlist, CurOwner);
  862. X
  863. X    if (PostViaMail) {
  864. X        Fprintf(sendmail, "%s: \"|%s -n %s\"\n",
  865. X        GroupasMail, CurMail2news, Ngroup);
  866. X        if (!EMPTY(CurOwner))
  867. X        Fprintf(sendmail, "owner-%s: %s\n", GroupasMail, CurOwner);
  868. X    }
  869. X    }
  870. X
  871. X    if (mmdf) {
  872. X    Fprintf(mmdf, "\n## %s <==> %s gateway\n", Ngroup, Mlist);
  873. X    Fprintf(mmdf, "%s%s: %s@%s\n",
  874. X        CurDoMailinglist ? "" : "#", Mlist, Mlist, CurMailhost);
  875. X    Fprintf(mmdf, "post-%s: \"%s|%s -n %s",
  876. X        Mlist, CurUser, CurMail2news, Ngroup);
  877. X    if (!EMPTY(CurOrganization))
  878. X        Fprintf(mmdf, " -o '%s'", CurOrganization);
  879. X    if (!EMPTY(CurFlags))
  880. X        Fprintf(mmdf, " %s", CurFlags);
  881. X    if (!EMPTY(CurModerator))
  882. X        Fprintf(mmdf, " -a %s", CurModerator);
  883. X    Fprintf(mmdf, "\"\n");
  884. X
  885. X    if (PostViaMail)
  886. X        Fprintf(mmdf, "%s: \"%s|%s -n %s\"\n",
  887. X        GroupasMail, CurUser, CurMail2news, Ngroup);
  888. X    }
  889. X
  890. X    if (ppuser) {
  891. X    Fprintf(ppuser, "\n## %s <==> %s gateway\n", Ngroup, Mlist);
  892. X    Fprintf(ppuser, "%s%s:822 %s@%s\n",
  893. X        CurDoMailinglist ? "" : "#", Mlist, Mlist, CurMailhost);
  894. X    Fprintf(ppuser, "post-%s: shell\n",
  895. X        Mlist, CurUser, CurMail2news, Ngroup);
  896. X    if (PostViaMail)
  897. X        Fprintf(ppuser, "%s:shell\n",
  898. X        GroupasMail, CurUser, CurMail2news, Ngroup);
  899. X    }  
  900. X
  901. X    if (ppshell) {
  902. X    Fprintf(ppshell, "\n## %s <==> %s gateway\n", Ngroup, Mlist);
  903. X    Fprintf(ppshell, "post-%s:%s,,%s -n %s",
  904. X        Mlist, CurUser, CurMail2news, Ngroup);
  905. X    if (!EMPTY(CurOrganization))
  906. X        Fprintf(ppshell, " -o '%s'", CurOrganization);
  907. X    if (!EMPTY(CurFlags))
  908. X        Fprintf(ppshell, " %s", CurFlags);
  909. X    if (!EMPTY(CurModerator))
  910. X        Fprintf(ppshell, " -a %s", CurModerator);
  911. X    Fprintf(ppshell, "\n");
  912. X    if (PostViaMail)
  913. X        Fprintf(ppshell, "%s:%s,,%s -n %s\n",
  914. X        GroupasMail, CurUser, CurMail2news, Ngroup);
  915. X    }  
  916. X
  917. X    if (news) {
  918. X    if (CurSite == NULL)
  919. X        Fprintf(stderr, "No site for newsgroup %s\n", Ngroup);
  920. X    else {
  921. X        /* Psuedo-site name and distributions. */
  922. X        Fprintf(news, "%s\\\n  :", CurSite);
  923. X        for (p = CurDistribs; *p; p++)
  924. X        Fprintf(news, "%s,!%s.all,", *p, *p);
  925. X        Fprintf(news, "%s,!%s.all\\\n ", Ngroup, Ngroup);
  926. X
  927. X        /* Command invocation. */
  928. X        if (CurRequestAddr)
  929. X        Fprintf(news, "  ::%s %s %s %s %s %%s\n",
  930. X            CurNews2mail, Mlist, CurMailcontact, CurRequestAddr,
  931. X            CurMailhost);
  932. X        else
  933. X        Fprintf(news, "  ::%s %s %s %s-request %s %%s\n",
  934. X            CurNews2mail, Mlist, CurMailcontact, CurMailcontact,
  935. X            CurMailhost);
  936. X    }
  937. X    }
  938. X
  939. X    /* Clean up. */
  940. X    free(GroupasMail);
  941. X}
  942. X
  943. X
  944. X/*
  945. X**  Open a file, or use - for standard output.  Write the prolog.
  946. X*/
  947. XSTATIC FILE *
  948. Xopenfile(name, timestring)
  949. X    char    *name;
  950. X    char    *timestring;
  951. X{
  952. X    FILE    *F;
  953. X
  954. X    if (EQ(name, "-"))
  955. X    F = stdout;
  956. X    else if ((F = fopen(name, "w")) == NULL) {
  957. X    Fprintf(stderr, "%s:  Can't open \"%s\" for output, %s.\n",
  958. X        Pname, name, strerror(errno));
  959. X    exit(1);
  960. X    }
  961. X
  962. X    /* Write prolog. */
  963. X    Fprintf(F, "##  %s\n", "--START-OF-GATEWAY-OUTPUT-");
  964. X    Fprintf(F, "##  Created at %s", timestring);
  965. X    Fprintf(F, "##  %s\n",
  966. X    "This section of the file has been built automatically.");
  967. X    Fprintf(F, "##  %s\n",
  968. X    "If you make any changes here they will be lost when it is rebuilt.");
  969. X
  970. X    return F;
  971. X}
  972. X
  973. X
  974. X/*
  975. X**  Close a file, write the epilog.
  976. X*/
  977. XSTATIC void
  978. Xclosefile(F)
  979. X    FILE    *F;
  980. X{
  981. X    if (F) {
  982. X    Fprintf(bbn, "##  %s\n", "--END-OF-GATEWAY-OUTPUT-");
  983. X    if (F != stdout)
  984. X        (void)fclose(F);
  985. X    }
  986. X}
  987. X
  988. X
  989. XSTATIC void
  990. XUsage()
  991. X{
  992. X    Fprintf(stderr, "Usage:\n\t%s %s\n\t\t%s input\n",
  993. X        Pname,
  994. X        "[-b] [-p] [-d dir] [-b bbn] [-m mmdf] [-n news]",
  995. X        "[-s sendmail] [-t PP_shell] [-u PP_user]");
  996. X    exit(1);
  997. X}
  998. X
  999. X
  1000. Xmain(ac, av)
  1001. X    int        ac;
  1002. X    char    *av[];
  1003. X{
  1004. X    int        c;
  1005. X    time_t    now;
  1006. X    char    *timestring;
  1007. X
  1008. X    /* Set defaults. */
  1009. X    Pname = (Pname = RDX(av[0], '/')) ? Pname + 1 : av[0];
  1010. X    (void)umask(0);
  1011. X    now = time((time_t *)NULL);
  1012. X    timestring = ctime(&now);
  1013. X
  1014. X    /* Parse JCL. */
  1015. X    while ((c = getopt(ac, av, "ab:m:n:ps:t:u:")) != EOF)
  1016. X    switch (c) {
  1017. X    default:
  1018. X        Usage();
  1019. X        /* NOTREACHED */
  1020. X    case 'a':
  1021. X        NoGroupCheck = TRUE;
  1022. X        break;
  1023. X    case 'b':
  1024. X        bbn = openfile(optarg, timestring);
  1025. X        break;
  1026. X    case 'd':
  1027. X        OutDir = optarg;
  1028. X        break;
  1029. X    case 'm':
  1030. X        mmdf = openfile(optarg, timestring);
  1031. X        break;
  1032. X    case 'n':
  1033. X        news = openfile(optarg, timestring);
  1034. X        break;
  1035. X    case 'p':
  1036. X        PostViaMail++;
  1037. X        break;
  1038. X    case 's':
  1039. X        sendmail = openfile(optarg, timestring);
  1040. X        break;
  1041. X    case 't':
  1042. X        ppshell = openfile(optarg, timestring);
  1043. X        break;
  1044. X    case 'u':
  1045. X        ppuser = openfile(optarg, timestring);
  1046. X        break;
  1047. X    }
  1048. X
  1049. X    /* Get input. */
  1050. X    ac -= optind;
  1051. X    av += optind;
  1052. X    if (ac != 0 && ac != 1)
  1053. X    Usage();
  1054. X    yyopen(av[0]);
  1055. X
  1056. X
  1057. X    /* Do the work. */
  1058. X    (void)yyparse();
  1059. X
  1060. X    /* Close files. */
  1061. X    closefile(bbn);
  1062. X    closefile(mmdf);
  1063. X    closefile(news);
  1064. X    closefile(sendmail);
  1065. X    closefile(ppuser);
  1066. X    closefile(ppshell);
  1067. X
  1068. X    /* That's all she wrote... */
  1069. X    exit(Errors == 0 ? 0 : 1);
  1070. X    /* NOTREACHED */
  1071. X}
  1072. END_OF_FILE
  1073.   if test 14642 -ne `wc -c <'gag.y'`; then
  1074.     echo shar: \"'gag.y'\" unpacked with wrong size!
  1075.   fi
  1076.   # end of 'gag.y'
  1077. fi
  1078. if test -f 'regex.c' -a "${1}" != "-c" ; then 
  1079.   echo shar: Will not clobber existing file \"'regex.c'\"
  1080. else
  1081.   echo shar: Extracting \"'regex.c'\" \(19043 characters\)
  1082.   sed "s/^X//" >'regex.c' <<'END_OF_FILE'
  1083. X#ifndef    lint
  1084. Xstatic char RCS[] =
  1085. X    "$Header: /nfs/papaya/u2/rsalz/src/newsgate/src/RCS/regex.c,v 1.3 89/07/10 12:20:12 rsalz Exp $";
  1086. X#endif    /* lint */
  1087. X/*
  1088. X * regex - Regular expression pattern matching
  1089. X *         and replacement
  1090. X *
  1091. X *
  1092. X * By:  Ozan S. Yigit (oz)
  1093. X *      Dept. of Computer Science
  1094. X *      York University
  1095. X *
  1096. X *
  1097. X * These routines are the PUBLIC DOMAIN equivalents 
  1098. X * of regex routines as found in 4.nBSD UN*X, with minor
  1099. X * extensions.
  1100. X *
  1101. X * These routines are derived from various implementations
  1102. X * found in software tools books, and Conroy's grep. They
  1103. X * are NOT derived from licensed/restricted software.
  1104. X * For more interesting/academic/complicated implementations,
  1105. X * see Henry Spencer's regexp routines, or GNU Emacs pattern
  1106. X * matching module.
  1107. X *
  1108. X * Routines:
  1109. X *      re_comp:        compile a regular expression into
  1110. X *                      a DFA.
  1111. X *
  1112. X *            char *re_comp(s)
  1113. X *            char *s;
  1114. X *
  1115. X *      re_exec:        execute the DFA to match a pattern.
  1116. X *
  1117. X *            int re_exec(s)
  1118. X *            char *s;
  1119. X *
  1120. X *    re_modw        change re_exec's understanding of what
  1121. X *            a "word" looks like (for \< and \>)
  1122. X *            by adding into the hidden word-character 
  1123. X *            table.
  1124. X *
  1125. X *            void re_modw(s)
  1126. X *            char *s;
  1127. X *
  1128. X *      re_subs:    substitute the matched portions in
  1129. X *                  a new string.
  1130. X *
  1131. X *            int re_subs(src, dst)
  1132. X *            char *src;
  1133. X *            char *dst;
  1134. X *
  1135. X *    re_fail:    failure routine for re_exec.
  1136. X *
  1137. X *            void re_fail(msg, op)
  1138. X *            char *msg;
  1139. X *            char op;
  1140. X *  
  1141. X * Regular Expressions:
  1142. X *
  1143. X *      [1]     char    matches itself, unless it is a special
  1144. X *                      character (metachar): . \ [ ] * + ^ $
  1145. X *
  1146. X *      [2]     .       matches any character.
  1147. X *
  1148. X *      [3]     \       matches the character following it, except
  1149. X *            when followed by a left or right round bracket,
  1150. X *            a digit 1 to 9 or a left or right angle bracket. 
  1151. X *            (see [7], [8] and [9])
  1152. X *            It is used as an escape character for all 
  1153. X *            other meta-characters, and itself. When used
  1154. X *            in a set ([4]), it is treated as an ordinary
  1155. X *            character.
  1156. X *
  1157. X *      [4]     [set]   matches one of the characters in the set.
  1158. X *                      If the first character in the set is "^",
  1159. X *                      it matches a character NOT in the set. A
  1160. X *                      shorthand S-E is used to specify a set of
  1161. X *                      characters S upto E, inclusive. The special
  1162. X *                      characters "]" and "-" have no special
  1163. X *                      meaning if they appear as the first chars
  1164. X *                      in the set.
  1165. X *                      examples:        match:
  1166. X *
  1167. X *                              [a-z]    any lowercase alpha
  1168. X *
  1169. X *                              [^]-]    any char except ] and -
  1170. X *
  1171. X *                              [^A-Z]   any char except uppercase
  1172. X *                                       alpha
  1173. X *
  1174. X *                              [a-zA-Z] any alpha
  1175. X *
  1176. X *      [5]     *       any regular expression form [1] to [4], followed by
  1177. X *                      closure char (*) matches zero or more matches of
  1178. X *                      that form.
  1179. X *
  1180. X *      [6]     +       same as [5], except it matches one or more.
  1181. X *
  1182. X *      [7]             a regular expression in the form [1] to [10], enclosed
  1183. X *                      as \(form\) matches what form matches. The enclosure
  1184. X *                      creates a set of tags, used for [8] and for
  1185. X *                      pattern substution. The tagged forms are numbered
  1186. X *            starting from 1.
  1187. X *
  1188. X *      [8]             a \ followed by a digit 1 to 9 matches whatever a
  1189. X *                      previously tagged regular expression ([7]) matched.
  1190. X *
  1191. X *    [9]    \<    a regular expression starting with a \< construct
  1192. X *        \>    and/or ending with a \> construct, restricts the
  1193. X *            pattern matching to the beginning of a word, and/or
  1194. X *            the end of a word. A word is defined to be a character
  1195. X *            string beginning and/or ending with the characters
  1196. X *            A-Z a-z 0-9 and _. It must also be preceded and/or
  1197. X *            followed by any character outside those mentioned.
  1198. X *
  1199. X *      [10]            a composite regular expression xy where x and y
  1200. X *                      are in the form [1] to [10] matches the longest
  1201. X *                      match of x followed by a match for y.
  1202. X *
  1203. X *      [11]    ^    a regular expression starting with a ^ character
  1204. X *        $    and/or ending with a $ character, restricts the
  1205. X *                      pattern matching to the beginning of the line,
  1206. X *                      or the end of line. [anchors] Elsewhere in the
  1207. X *            pattern, ^ and $ are treated as ordinary characters.
  1208. X *
  1209. X *
  1210. X * Acknowledgements:
  1211. X *
  1212. X *    HCR's Hugh Redelmeier has been most helpful in various
  1213. X *    stages of development. He convinced me to include BOW
  1214. X *    and EOW constructs, originally invented by Rob Pike at
  1215. X *    the University of Toronto.
  1216. X *
  1217. X * References:
  1218. X *              Software tools            Kernighan & Plauger
  1219. X *              Software tools in Pascal        Kernighan & Plauger
  1220. X *              Grep [rsx-11 C dist]            David Conroy
  1221. X *        ed - text editor        Un*x Programmer's Manual
  1222. X *        Advanced editing on Un*x    B. W. Kernighan
  1223. X *        RegExp routines            Henry Spencer
  1224. X *
  1225. X * Notes:
  1226. X *
  1227. X *    This implementation uses a bit-set representation for character
  1228. X *    classes for speed and compactness. Each character is represented 
  1229. X *    by one bit in a 128-bit block. Thus, CCL or NCL always takes a 
  1230. X *    constant 16 bytes in the internal dfa, and re_exec does a single
  1231. X *    bit comparison to locate the character in the set.
  1232. X *
  1233. X * Examples:
  1234. X *
  1235. X *    pattern:    foo*.*
  1236. X *    compile:    CHR f CHR o CLO CHR o END CLO ANY END END
  1237. X *    matches:    fo foo fooo foobar fobar foxx ...
  1238. X *
  1239. X *    pattern:    fo[ob]a[rz]    
  1240. X *    compile:    CHR f CHR o CCL 2 o b CHR a CCL bitset END
  1241. X *    matches:    fobar fooar fobaz fooaz
  1242. X *
  1243. X *    pattern:    foo\\+
  1244. X *    compile:    CHR f CHR o CHR o CHR \ CLO CHR \ END END
  1245. X *    matches:    foo\ foo\\ foo\\\  ...
  1246. X *
  1247. X *    pattern:    \(foo\)[1-3]\1    (same as foo[1-3]foo)
  1248. X *    compile:    BOT 1 CHR f CHR o CHR o EOT 1 CCL bitset REF 1 END
  1249. X *    matches:    foo1foo foo2foo foo3foo
  1250. X *
  1251. X *    pattern:    \(fo.*\)-\1
  1252. X *    compile:    BOT 1 CHR f CHR o CLO ANY END EOT 1 CHR - REF 1 END
  1253. X *    matches:    foo-foo fo-fo fob-fob foobar-foobar ...
  1254. X * 
  1255. X */
  1256. X
  1257. X#define MAXDFA  1024
  1258. X#define MAXTAG  10
  1259. X
  1260. X#define OKP     1
  1261. X#define NOP     0
  1262. X
  1263. X#define CHR     1
  1264. X#define ANY     2
  1265. X#define CCL     3
  1266. X#define NCL     4
  1267. X#define BOL     5
  1268. X#define EOL     6
  1269. X#define BOT     7
  1270. X#define EOT     8
  1271. X#define BOW    9
  1272. X#define EOW    10
  1273. X#define REF     11
  1274. X#define CLO     12
  1275. X
  1276. X#define END     0
  1277. X
  1278. X/*
  1279. X * The following defines are not meant
  1280. X * to be changeable. They are for readibility
  1281. X * only.
  1282. X *
  1283. X */
  1284. X#define MAXCHR    128
  1285. X#define CHRBIT    8
  1286. X#define BITBLK    MAXCHR/CHRBIT
  1287. X#define BLKIND    0170
  1288. X#define BITIND    07
  1289. X
  1290. X#define ASCIIB    0177
  1291. X
  1292. Xtypedef /*unsigned*/ char CHAR;
  1293. X
  1294. Xstatic int  tagstk[MAXTAG];             /* subpat tag stack..*/
  1295. Xstatic CHAR dfa[MAXDFA];        /* automaton..       */
  1296. Xstatic int  sta = NOP;                   /* status of lastpat */
  1297. X
  1298. Xstatic CHAR bittab[BITBLK];        /* bit table for CCL */
  1299. X
  1300. Xstatic void
  1301. Xchset(c) register CHAR c; { bittab[((c)&BLKIND)>>3] |= 1<<((c)&BITIND); }
  1302. X
  1303. X#define badpat(x)    return(*dfa = END, x)
  1304. X#define store(x)    *mp++ = x
  1305. Xchar *     
  1306. Xre_comp(pat)
  1307. Xchar *pat;
  1308. X{
  1309. X    register char *p;               /* pattern pointer   */
  1310. X    register CHAR *mp=dfa;          /* dfa pointer       */
  1311. X    register CHAR *lp;              /* saved pointer..   */
  1312. X    register CHAR *sp=dfa;          /* another one..     */
  1313. X
  1314. X    register int tagi = 0;          /* tag stack index   */
  1315. X    register int tagc = 1;          /* actual tag count  */
  1316. X
  1317. X    register int n;
  1318. X    int c1, c2;
  1319. X        
  1320. X    if (!pat || !*pat)
  1321. X        if (sta)
  1322. X            return(0);
  1323. X        else
  1324. X            badpat("No previous regular expression");
  1325. X    sta = NOP;
  1326. X
  1327. X    for (p = pat; *p; p++) {
  1328. X        lp = mp;
  1329. X        switch(*p) {
  1330. X
  1331. X        case '.':               /* match any char..  */
  1332. X            store(ANY);
  1333. X            break;
  1334. X
  1335. X        case '^':               /* match beginning.. */
  1336. X            if (p == pat)
  1337. X                store(BOL);
  1338. X            else {
  1339. X                store(CHR);
  1340. X                store(*p);
  1341. X            }
  1342. X            break;
  1343. X
  1344. X        case '$':               /* match endofline.. */
  1345. X            if (!*(p+1))
  1346. X                store(EOL);
  1347. X            else {
  1348. X                store(CHR);
  1349. X                store(*p);
  1350. X            }
  1351. X            break;
  1352. X
  1353. X        case '[':               /* match char class..*/
  1354. X
  1355. X            if (*++p == '^') {
  1356. X                store(NCL);
  1357. X                p++;
  1358. X            }
  1359. X            else
  1360. X                store(CCL);
  1361. X
  1362. X            if (*p == '-')        /* real dash */
  1363. X                chset(*p++);
  1364. X            if (*p == ']')        /* real brac */
  1365. X                chset(*p++);
  1366. X            while (*p && *p != ']') {
  1367. X                if (*p == '-' && *(p+1) && *(p+1) != ']') {
  1368. X                    p++;
  1369. X                    c1 = *(p-2) + 1;
  1370. X                    c2 = *p++;
  1371. X                    while (c1 <= c2)
  1372. X                        chset(c1++);
  1373. X                }
  1374. X#ifdef EXTEND
  1375. X                else if (*p == '\\' && *(p+1)) {
  1376. X                    p++;
  1377. X                    chset(*p++);
  1378. X                }
  1379. X#endif
  1380. X                else
  1381. X                    chset(*p++);
  1382. X            }
  1383. X            if (!*p)
  1384. X                badpat("Missing ]");
  1385. X
  1386. X            for (n = 0; n < BITBLK; bittab[n++] = (char) 0)
  1387. X                store(bittab[n]);
  1388. X    
  1389. X            break;
  1390. X
  1391. X        case '*':               /* match 0 or more.. */
  1392. X        case '+':               /* match 1 or more.. */
  1393. X            if (p == pat)
  1394. X                badpat("Empty closure");
  1395. X            lp = sp;                /* previous opcode */
  1396. X            if (*lp == CLO)         /* equivalence..   */
  1397. X                break;
  1398. X            switch(*lp) {
  1399. X
  1400. X            case BOL:
  1401. X            case BOT:
  1402. X            case EOT:
  1403. X            case BOW:
  1404. X            case EOW:
  1405. X            case REF:
  1406. X                badpat("Illegal closure");
  1407. X            default:
  1408. X                break;
  1409. X            }
  1410. X
  1411. X            if (*p == '+')
  1412. X                for (sp = mp; lp < sp; lp++)
  1413. X                    store(*lp);
  1414. X
  1415. X            store(END);
  1416. X            store(END);
  1417. X            sp = mp;
  1418. X            while (--mp > lp)
  1419. X                *mp = mp[-1];
  1420. X            store(CLO);
  1421. X            mp = sp;
  1422. X            break;
  1423. X
  1424. X        case '\\':              /* tags, backrefs .. */
  1425. X            switch(*++p) {
  1426. X
  1427. X            case '(':
  1428. X                if (tagc < MAXTAG) {
  1429. X                    tagstk[++tagi] = tagc;
  1430. X                    store(BOT);
  1431. X                    store(tagc++);
  1432. X                }
  1433. X                else
  1434. X                    badpat("Too many \\(\\) pairs");
  1435. X                break;
  1436. X            case ')':
  1437. X                if (*sp == BOT)
  1438. X                    badpat("Null pattern inside \\(\\)");
  1439. X                if (tagi > 0) {
  1440. X                    store(EOT);
  1441. X                    store(tagstk[tagi--]);
  1442. X                }
  1443. X                else
  1444. X                    badpat("Unmatched \\)");
  1445. X                break;
  1446. X            case '<':
  1447. X                store(BOW);
  1448. X                break;
  1449. X            case '>':
  1450. X                if (*sp == BOW)
  1451. X                    badpat("Null pattern inside \\<\\>");
  1452. X                store(EOW);
  1453. X                break;
  1454. X            case '1':
  1455. X            case '2':
  1456. X            case '3':
  1457. X            case '4':
  1458. X            case '5':
  1459. X            case '6':
  1460. X            case '7':
  1461. X            case '8':
  1462. X            case '9':
  1463. X                n = *p-'0';
  1464. X                if (tagi > 0 && tagstk[tagi] == n)
  1465. X                    badpat("Cyclical reference");
  1466. X                if (tagc > n) {
  1467. X                    store(REF);
  1468. X                    store(n);
  1469. X                }
  1470. X                else
  1471. X                    badpat("Undetermined reference");
  1472. X                break;
  1473. X#ifdef EXTEND
  1474. X            case 'b':
  1475. X                store(CHR);
  1476. X                store('\b');
  1477. X                break;
  1478. X            case 'n':
  1479. X                store(CHR);
  1480. X                store('\n');
  1481. X                break;
  1482. X            case 'f':
  1483. X                store(CHR);
  1484. X                store('\f');
  1485. X                break;
  1486. X            case 'r':
  1487. X                store(CHR);
  1488. X                store('\r');
  1489. X                break;
  1490. X            case 't':
  1491. X                store(CHR);
  1492. X                store('\t');
  1493. X                break;
  1494. X#endif
  1495. X            default:
  1496. X                store(CHR);
  1497. X                store(*p);
  1498. X            }
  1499. X            break;
  1500. X
  1501. X        default :               /* an ordinary char  */
  1502. X            store(CHR);
  1503. X            store(*p);
  1504. X            break;
  1505. X        }
  1506. X        sp = lp;
  1507. X    }
  1508. X    if (tagi > 0)
  1509. X        badpat("Unmatched \\(");
  1510. X    store(END);
  1511. X    sta = OKP;
  1512. X    return(0);
  1513. X}
  1514. X
  1515. X
  1516. Xstatic char *bol;
  1517. Xstatic char *bopat[MAXTAG];
  1518. Xstatic char *eopat[MAXTAG];
  1519. Xchar *pmatch();
  1520. X
  1521. X/*
  1522. X * re_exec:
  1523. X *     execute dfa to find a match.
  1524. X *
  1525. X *    special cases: (dfa[0])    
  1526. X *        BOL
  1527. X *            Match only once, starting from the
  1528. X *            beginning.
  1529. X *        CHR
  1530. X *            First locate the character without
  1531. X *            calling pmatch, and if found, call
  1532. X *            pmatch for the remaining string.
  1533. X *        END
  1534. X *            re_comp failed, poor luser did not
  1535. X *            check for it. Fail fast.
  1536. X *
  1537. X *    If a match is found, bopat[0] and eopat[0] are set
  1538. X *    to the beginning and the end of the matched fragment,
  1539. X *    respectively.
  1540. X *
  1541. X */
  1542. X
  1543. Xint
  1544. Xre_exec(lp)
  1545. Xregister char *lp;
  1546. X{
  1547. X    register char c;
  1548. X    register char *ep = 0;
  1549. X    register CHAR *ap = dfa;
  1550. X
  1551. X    bol = lp;
  1552. X
  1553. X    bopat[0] = 0;
  1554. X    bopat[1] = 0;
  1555. X    bopat[2] = 0;
  1556. X    bopat[3] = 0;
  1557. X    bopat[4] = 0;
  1558. X    bopat[5] = 0;
  1559. X    bopat[6] = 0;
  1560. X    bopat[7] = 0;
  1561. X    bopat[8] = 0;
  1562. X    bopat[9] = 0;
  1563. X
  1564. X    switch(*ap) {
  1565. X
  1566. X    case BOL:            /* anchored: match from BOL only */
  1567. X        ep = pmatch(lp,ap);
  1568. X        break;
  1569. X    case CHR:            /* ordinary char: locate it fast */
  1570. X        c = *(ap+1);
  1571. X        while (*lp && *lp != c)
  1572. X            lp++;
  1573. X        if (!*lp)        /* if EOS, fail, else fall thru. */
  1574. X            return(0);
  1575. X    default:            /* regular matching all the way. */
  1576. X        while (*lp) {
  1577. X            if ((ep = pmatch(lp,ap)))
  1578. X                break;
  1579. X            lp++;
  1580. X        }
  1581. X        break;
  1582. X    case END:            /* munged automaton. fail always */
  1583. X        return(0);
  1584. X    }
  1585. X    if (!ep)
  1586. X        return(0);
  1587. X
  1588. X    bopat[0] = lp;
  1589. X    eopat[0] = ep;
  1590. X    return(1);
  1591. X}
  1592. X
  1593. X/* 
  1594. X * pmatch: 
  1595. X *    internal routine for the hard part
  1596. X *
  1597. X *     This code is mostly snarfed from an early
  1598. X *     grep written by David Conroy. The backref and
  1599. X *     tag stuff, and various other mods are by oZ.
  1600. X *
  1601. X *    special cases: (dfa[n], dfa[n+1])
  1602. X *        CLO ANY
  1603. X *            We KNOW ".*" will match ANYTHING
  1604. X *            upto the end of line. Thus, go to
  1605. X *            the end of line straight, without
  1606. X *            calling pmatch recursively. As in
  1607. X *            the other closure cases, the remaining
  1608. X *            pattern must be matched by moving
  1609. X *            backwards on the string recursively,
  1610. X *            to find a match for xy (x is ".*" and 
  1611. X *            y is the remaining pattern) where
  1612. X *            the match satisfies the LONGEST match
  1613. X *            for x followed by a match for y.
  1614. X *        CLO CHR
  1615. X *            We can again scan the string forward
  1616. X *            for the single char without recursion, 
  1617. X *            and at the point of failure, we execute 
  1618. X *            the remaining dfa recursively, as
  1619. X *            described above.
  1620. X *
  1621. X *    At the end of a successful match, bopat[n] and eopat[n]
  1622. X *    are set to the beginning and end of subpatterns matched
  1623. X *    by tagged expressions (n = 1 to 9).    
  1624. X *
  1625. X */
  1626. X
  1627. Xextern void re_fail();
  1628. X
  1629. X/*
  1630. X * character classification table for word boundary
  1631. X * operators BOW and EOW. the reason for not using 
  1632. X * ctype macros is that we can let the user add into 
  1633. X * our own table. see re_modw. This table is not in
  1634. X * the bitset form, since we may wish to extend it
  1635. X * in the future for other character classifications. 
  1636. X *
  1637. X *    TRUE for 0-9 A-Z a-z _
  1638. X */
  1639. Xstatic char chrtyp[MAXCHR] = {
  1640. X    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
  1641. X    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
  1642. X    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
  1643. X    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
  1644. X    0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 
  1645. X    1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 
  1646. X    0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 
  1647. X    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 
  1648. X    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 
  1649. X    1, 0, 0, 0, 0, 1, 0, 1, 1, 1, 
  1650. X    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 
  1651. X    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 
  1652. X    1, 1, 1, 0, 0, 0, 0, 0
  1653. X    };
  1654. X
  1655. X#define inascii(x)    (0177&(x))
  1656. X#define iswordc(x)     chrtyp[inascii(x)]
  1657. X#define isinset(x,y)     ((x)[((y)&BLKIND)>>3] & (1<<((y)&BITIND)))
  1658. X
  1659. X/*
  1660. X * skip values for CLO XXX to skip past the closure
  1661. X *
  1662. X */
  1663. X
  1664. X#define ANYSKIP    2     /* CLO ANY END ...       */
  1665. X#define CHRSKIP    3    /* CLO CHR chr END ...       */
  1666. X#define CCLSKIP 18    /* CLO CCL 16bytes END ... */
  1667. X
  1668. Xstatic char *
  1669. Xpmatch(lp, ap)
  1670. Xregister char *lp;
  1671. Xregister CHAR *ap;
  1672. X{
  1673. X    register char *e;        /* extra pointer for CLO */
  1674. X    register char *bp;        /* beginning of subpat.. */
  1675. X    register char *ep;        /* ending of subpat..     */
  1676. X    register int op, c, n;
  1677. X    char *are;            /* to save the line ptr. */
  1678. X
  1679. X    while ((op = *ap++) != END)
  1680. X        switch(op) {
  1681. X
  1682. X        case CHR:
  1683. X            if (*lp++ != *ap++)
  1684. X                return(0);
  1685. X            break;
  1686. X        case ANY:
  1687. X            if (!*lp++)
  1688. X                return(0);
  1689. X            break;
  1690. X        case CCL:
  1691. X            c = *lp++;
  1692. X            if (!isinset(ap,c))
  1693. X                return(0);
  1694. X            ap += BITBLK;
  1695. X            break;
  1696. X        case NCL:
  1697. X            c = *lp++;
  1698. X            if (isinset(ap,c))
  1699. X                return(0);
  1700. X            ap += BITBLK;
  1701. X            break;
  1702. X        case BOL:
  1703. X            if (lp != bol)
  1704. X                return(0);
  1705. X            break;
  1706. X        case EOL:
  1707. X            if (*lp)
  1708. X                return(0);
  1709. X            break;
  1710. X        case BOT:
  1711. X            bopat[*ap++] = lp;
  1712. X            break;
  1713. X        case EOT:
  1714. X            eopat[*ap++] = lp;
  1715. X            break;
  1716. X         case BOW:
  1717. X            if (!(lp!=bol && iswordc(lp[-1])) && iswordc(*lp))
  1718. X                break;
  1719. X            return(0);
  1720. X        case EOW:
  1721. X            if ((lp!=bol && iswordc(lp[-1])) && !iswordc(*lp))
  1722. X                break;
  1723. X            return(0);
  1724. X        case REF:
  1725. X            n = *ap++;
  1726. X            bp = bopat[n];
  1727. X            ep = eopat[n];
  1728. X            while (bp < ep)
  1729. X                if (*bp++ != *lp++)
  1730. X                    return(0);
  1731. X            break;
  1732. X        case CLO:
  1733. X            are = lp;
  1734. X            switch(*ap) {
  1735. X
  1736. X            case ANY:
  1737. X                while (*lp)
  1738. X                    lp++;
  1739. X                n = ANYSKIP;
  1740. X                break;
  1741. X            case CHR:
  1742. X                c = *(ap+1);
  1743. X                while (*lp && c == *lp)
  1744. X                    lp++;
  1745. X                n = CHRSKIP;
  1746. X                break;
  1747. X            case CCL:
  1748. X            case NCL:
  1749. X                while (*lp && (e = pmatch(lp, ap)))
  1750. X                    lp = e;
  1751. X                n = CCLSKIP;
  1752. X                break;
  1753. X            default:
  1754. X                re_fail("closure: bad dfa.", *ap);
  1755. X                return(0);
  1756. X            }
  1757. X
  1758. X            ap += n;
  1759. X
  1760. X            while (lp >= are) {
  1761. X                if (e = pmatch(lp, ap))
  1762. X                    return(e);
  1763. X                --lp;
  1764. X            }
  1765. X            return(0);
  1766. X        default:
  1767. X            re_fail("re_exec: bad dfa.", op);
  1768. X            return(0);
  1769. X        }
  1770. X    return(lp);
  1771. X}
  1772. X
  1773. X/*
  1774. X * re_modw:
  1775. X *    add new characters into the word table to
  1776. X *    change the re_exec's understanding of what
  1777. X *    a word should look like. Note that we only
  1778. X *    accept additions into the word definition.
  1779. X *
  1780. X *    If the string parameter is 0 or null string,
  1781. X *    the table is reset back to the default, which
  1782. X *    contains A-Z a-z 0-9 _. [We use the compact
  1783. X *    bitset representation for the default table]
  1784. X *
  1785. X */
  1786. X
  1787. Xstatic char deftab[16] = {    
  1788. X    0, 0, 0, 0, 0, 0, 377, 003, 376, 377, 377, 207,  
  1789. X    376, 377, 377, 007 
  1790. X}; 
  1791. X
  1792. Xvoid
  1793. Xre_modw(s)
  1794. Xregister char *s;
  1795. X{
  1796. X    register int i;
  1797. X
  1798. X    if (!s || !*s) {
  1799. X        for (i = 0; i < MAXCHR; i++)
  1800. X            if (!isinset(deftab,i))
  1801. X                iswordc(i) = 0;
  1802. X    }
  1803. X    else
  1804. X        while(*s)
  1805. X            iswordc(*s++) = 1;
  1806. X}
  1807. X
  1808. X/*
  1809. X * re_subs:
  1810. X *    substitute the matched portions of the src in
  1811. X *    dst.
  1812. X *
  1813. X *    &    substitute the entire matched pattern.
  1814. X *
  1815. X *    \digit    substitute a subpattern, with the given
  1816. X *        tag number. Tags are numbered from 1 to
  1817. X *        9. If the particular tagged subpattern
  1818. X *        does not exist, null is substituted.
  1819. X *
  1820. X */
  1821. Xint
  1822. Xre_subs(src, dst)
  1823. Xregister char *src;
  1824. Xregister char *dst;
  1825. X{
  1826. X    register char c;
  1827. X    register int  pin;
  1828. X    register char *bp;
  1829. X    register char *ep;
  1830. X
  1831. X    if (!*src || !bopat[0])
  1832. X        return(0);
  1833. X
  1834. X    while (c = *src++) {
  1835. X        switch(c) {
  1836. X
  1837. X        case '&':
  1838. X            pin = 0;
  1839. X            break;
  1840. X
  1841. X        case '\\':
  1842. X            c = *src++;
  1843. X            if (c >= '0' && c <= '9') {
  1844. X                pin = c - '0';
  1845. X                break;
  1846. X            }
  1847. X            
  1848. X        default:
  1849. X            *dst++ = c;
  1850. X            continue;
  1851. X        }
  1852. X
  1853. X        if ((bp = bopat[pin]) && (ep = eopat[pin])) {
  1854. X            while (*bp && bp < ep)
  1855. X                *dst++ = *bp++;
  1856. X            if (bp < ep)
  1857. X                return(0);
  1858. X        }
  1859. X    }
  1860. X    *dst = (char) 0;
  1861. X    return(1);
  1862. X}
  1863. X            
  1864. X#ifdef DEBUG
  1865. X/*
  1866. X * symbolic - produce a symbolic dump of the
  1867. X *            dfa
  1868. X */
  1869. Xsymbolic(s) 
  1870. Xchar *s;
  1871. X{
  1872. X    (void)printf("pattern: %s\n", s);
  1873. X    (void)printf("dfacode:\n");
  1874. X    dfadump(dfa);
  1875. X}
  1876. X
  1877. Xstatic    
  1878. Xdfadump(ap)
  1879. XCHAR *ap;
  1880. X{
  1881. X    register int n;
  1882. X
  1883. X    while (*ap != END)
  1884. X        switch(*ap++) {
  1885. X        case CLO:
  1886. X            (void)printf("CLOSURE");
  1887. X            dfadump(ap);
  1888. X            switch(*ap) {
  1889. X            case CHR:
  1890. X                n = CHRSKIP;
  1891. X                break;
  1892. X            case ANY:
  1893. X                n = ANYSKIP;
  1894. X                break;
  1895. X            case CCL:
  1896. X            case NCL:
  1897. X                n = CCLSKIP;
  1898. X                break;
  1899. X            }
  1900. X            ap += n;
  1901. X            break;
  1902. X        case CHR:
  1903. X            (void)printf("\tCHR %c\n",*ap++);
  1904. X            break;
  1905. X        case ANY:
  1906. X            (void)printf("\tANY .\n");
  1907. X            break;
  1908. X        case BOL:
  1909. X            (void)printf("\tBOL -\n");
  1910. X            break;
  1911. X        case EOL:
  1912. X            (void)printf("\tEOL -\n");
  1913. X            break;
  1914. X        case BOT:
  1915. X            (void)printf("BOT: %d\n",*ap++);
  1916. X            break;
  1917. X        case EOT:
  1918. X            (void)printf("EOT: %d\n",*ap++);
  1919. X            break;
  1920. X        case BOW:
  1921. X            (void)printf("BOW\n");
  1922. X            break;
  1923. X        case EOW:
  1924. X            (void)printf("EOW\n");
  1925. X            break;
  1926. X        case REF:
  1927. X            (void)printf("REF: %d\n",*ap++);
  1928. X            break;
  1929. X        case CCL:
  1930. X            (void)printf("\tCCL [");
  1931. X            for (n = 0; n < MAXCHR; n++)
  1932. X                if (isinset(ap,(CHAR)n))
  1933. X                    (void)printf("%c",n);
  1934. X            (void)printf("]\n");
  1935. X            ap += BITBLK;
  1936. X            break;
  1937. X        case NCL:
  1938. X            (void)printf("\tNCL [");
  1939. X            for (n = 0; n < MAXCHR; n++)
  1940. X                if (isinset(ap,(CHAR)n))
  1941. X                    (void)printf("%c",n);
  1942. X            (void)printf("]\n");
  1943. X            ap += BITBLK;
  1944. X            break;
  1945. X        default:
  1946. X            (void)printf("bad dfa. opcode %o\n", ap[-1]);
  1947. X            exit(1);
  1948. X            break;
  1949. X        }
  1950. X}
  1951. X#endif
  1952. END_OF_FILE
  1953.   if test 19043 -ne `wc -c <'regex.c'`; then
  1954.     echo shar: \"'regex.c'\" unpacked with wrong size!
  1955.   fi
  1956.   # end of 'regex.c'
  1957. fi
  1958. echo shar: End of archive 1 \(of 4\).
  1959. cp /dev/null ark1isdone
  1960. MISSING=""
  1961. for I in 1 2 3 4 ; do
  1962.     if test ! -f ark${I}isdone ; then
  1963.     MISSING="${MISSING} ${I}"
  1964.     fi
  1965. done
  1966. if test "${MISSING}" = "" ; then
  1967.     echo You have unpacked all 4 archives.
  1968.     rm -f ark[1-9]isdone
  1969. else
  1970.     echo You still must unpack the following archives:
  1971.     echo "        " ${MISSING}
  1972. fi
  1973. exit 0
  1974. exit 0 # Just in case...
  1975.